package pers.kw.server.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import pers.kw.exceptions.BizException;
import pers.kw.protocol.R;
import pers.kw.server.config.DistributedLock;
import pers.kw.server.service.DistributedLockManager;
import pers.kw.server.service.StorageService;
import pers.kw.storage.api.StorageApi;
import pers.kw.storage.dto.UpdateStorageReqDto;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.concurrent.TimeUnit;

@Slf4j
@Api(tags = "库存服务")
@RestController
public class StorageController implements StorageApi {

    @Resource
    private StorageService storageService;

    @Override
    public R<String> updateStorage(UpdateStorageReqDto reqDto) {
        storageService.updateStorage(reqDto);
        return R.ok("更新库存成功");
    }

    @ApiOperation(value = "并发测试分布式锁")
    @PostMapping(value = "/storage/api/update/storage/concurrent")
    public R<String> batchUpdateStorage(@Valid @RequestBody UpdateStorageReqDto reqDto) throws InterruptedException {
        storageService.batchUpdateStorage(reqDto);
        return R.ok("更新库存成功");
    }


    @ApiOperation(value = "测试事务失效")
    @PostMapping(value = "/storage/api/update/storage/tx")
    public R<String> testTx(@Valid @RequestBody UpdateStorageReqDto reqDto) throws InterruptedException {
        storageService.testTx(reqDto);
        return R.ok("更新库存成功");
    }

    @Autowired
    private DistributedLockManager distributedLockManager;

    @ApiOperation(value = "分布式锁Lock")
    @PostMapping(value = "/storage/api/update/storage/tx/lock")
    public R<String> testTxLock(@Valid @RequestBody UpdateStorageReqDto reqDto) {
        distributedLockManager.lock("lockKey", () -> {
            //测试阻塞效果
            this.sleep(9);
            // 在锁保护的代码块内执行需要加锁的业务逻辑
            storageService.updateStorage(reqDto);
        });
        return R.ok("更新库存成功");
    }

    @ApiOperation(value = "分布式锁TryLock")
    @PostMapping(value = "/storage/api/update/storage/tx/tryLock")
    public R<String> testTxTryLock(@Valid @RequestBody UpdateStorageReqDto reqDto) {
        // 或者使用 tryLock 方法进行非阻塞的加锁
        distributedLockManager.tryLock("tryLockKey", 5, 10, TimeUnit.SECONDS, () -> {
            //测试阻塞效果
            this.sleep(2);
            // 在锁保护的代码块内执行需要加锁的业务逻辑
            storageService.updateStorage(reqDto);
        }, () -> {
            throw new BizException("等等吧~再试");
        });
        return R.ok("更新库存成功");
    }

    private void sleep(long timeout) {
        try {
            TimeUnit.SECONDS.sleep(timeout);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @DistributedLock(lockKey = "REPAY", scope = 1, errorTips = "等会儿")
    @ApiOperation(value = "分布式锁TryLock-注解方式实现")
    @PostMapping(value = "/storage/api/update/storage/tx/annotation")
    public R<String> annotationTx(@Valid @RequestBody UpdateStorageReqDto reqDto) {
        //测试阻塞效果
        this.sleep(10);
        log.info("处理业务逻辑。。。");
        //storageService.updateStorage(reqDto);
        return R.ok("更新库存成功");
    }
}
